package com.zzyl.nursing.service.impl;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.druid.support.json.JSONUtils;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.*;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.exception.ServiceException;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.DateUtils;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.common.utils.bean.BeanUtils;
import com.zzyl.common.utils.uuid.UUID;
import com.zzyl.nursing.domain.DeviceData;
import com.zzyl.nursing.dto.DeviceDto;
import com.zzyl.nursing.vo.DeviceDetailVo;
import com.zzyl.nursing.vo.DeviceShadowDataVo;
import com.zzyl.nursing.vo.ProductVo;
import com.zzyl.nursing.vo.iot.IotMsgHeader;
import com.zzyl.nursing.vo.iot.IotMsgNotifyData;
import com.zzyl.nursing.vo.iot.IotMsgService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.domain.Device;
import com.zzyl.nursing.service.IDeviceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import javax.annotation.Resource;
import java.util.stream.Collectors;

/**
 * 设备Service业务层处理
 * 
 * @author lhs
 * @date 2025-06-01
 */
@Slf4j
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements IDeviceService
{
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private RedisTemplate<String,String> redisTemplate;
    @Autowired
    private IoTDAClient  iotClient;

    /**
     * 查询设备
     * 
     * @param id 设备主键
     * @return 设备
     */
    @Override
    public Device selectDeviceById(Long id)
    {
        return getById(id);
    }

    /**
     * 查询设备列表
     * 
     * @param device 设备
     * @return 设备
     */
    @Override
    public List<Device> selectDeviceList(Device device)
    {
        return deviceMapper.selectDeviceList(device);
    }

    /**
     * 新增设备
     * 
     * @param device 设备
     * @return 结果
     */
    @Override
    public int insertDevice(Device device)
    {
        return save(device) ? 1 : 0;
    }

    /**
     * 修改设备
     * 
     * @param device 设备
     * @return 结果
     */
    @Override
    public int updateDevice(Device device)
    {
        return updateById(device) ? 1 : 0;
    }

    /**
     * 批量删除设备
     * 
     * @param ids 需要删除的设备主键
     * @return 结果
     */
    @Override
    public int deleteDeviceByIds(Long[] ids)
    {
        return removeByIds(Arrays.asList(ids)) ? 1 : 0;
    }

    /**
     * 删除设备信息
     * 
     * @param id 设备主键
     * @return 结果
     */
    @Override
    public int deleteDeviceById(Long id)
    {
        return removeById(id) ? 1 : 0;
    }

    @Override
    public void syncProductList() {
        //查询请求对象
        ListProductsRequest request = new ListProductsRequest();
        //执行查询
        ListProductsResponse response = iotClient.listProducts(request);
        //获取华为云平台上的产品列表
        List<ProductSummary> productsList = response.getProducts();
        if(response.getHttpStatusCode() != 200){
            throw new BaseException("物联网接口 - 查询产品，同步失败");
        }
        //转成vo
        List<ProductVo> productVoList = productsList.stream().map(product ->
                new ProductVo(product.getProductId(), product.getName())
        ).collect(Collectors.toList());
        //存入redis,传一个key，一个value，value是一个list我们需要存的集合
        redisTemplate.opsForValue().set(CacheConstants.ALL_PRODUCT_KEY, JSONUtil.toJsonStr( productVoList));
    }

    @Override
    public List<ProductVo> allProduct() {
        //从redis中获取数据
        String json = redisTemplate.opsForValue().get(CacheConstants.ALL_PRODUCT_KEY);
        //解析json
        List<ProductVo> productVoList = JSONUtil.toList(json, ProductVo.class);

        return productVoList;
    }

    @Override
    public void registerDevice(DeviceDto deviceDto) {
        //判断设备名字是否重复
        Long count = lambdaQuery().eq(Device::getDeviceName, deviceDto.getDeviceName()).count();
        if(count > 0){
            throw new ServiceException("设备名称重复");
        }
        //检验设备标识码是否重复
        count = lambdaQuery().eq(Device::getNodeId, deviceDto.getNodeId()).count();
        if(count > 0){
            throw new ServiceException("设备标识码重复");
        }
        //校验同一位置是否绑定同一产品
        count =lambdaQuery().eq(Device::getBindingLocation, deviceDto.getBindingLocation())
                .eq(Device::getLocationType, deviceDto.getLocationType())
                .eq(Device::getPhysicalLocationType,  deviceDto.getPhysicalLocationType())
                .count();
        if(count > 0){
            throw new ServiceException("同一位置只能绑定同一产品");
        }
        //请求华为云注册设备
        AddDeviceRequest addDeviceRequest = new AddDeviceRequest();
        AddDevice addDevice = new AddDevice();
        addDevice.setNodeId(deviceDto.getNodeId());
        addDevice.setProductId(deviceDto.getProductKey());
        addDevice.setDeviceName(deviceDto.getDeviceName());
        //获取密钥
        AuthInfo authInfo = new AuthInfo();
        authInfo.setSecret(UUID.fastUUID().toString(true));
        addDevice.setAuthInfo(authInfo);
        addDeviceRequest.setBody(addDevice);
        try {
            AddDeviceResponse response =iotClient.addDevice(addDeviceRequest);
            Device device = BeanUtil.toBean(deviceDto, Device.class);
            //设备id、设备绑定状态
            device.setIotId(response.getDeviceId());
            //秘钥
            device.setSecret(authInfo.getSecret());
            save(device);
        } catch (Exception e) {
            throw new ServiceException("注册出错了~");
        }
    }

    @Override
    public DeviceDetailVo getDeviceInfo(String iotId) {
        //根据IotId查询数据库
        Device device = lambdaQuery().eq(Device::getIotId, iotId).one();
        if (device == null){
            throw new ServiceException("设备不存在");
        }
        //把数据库的数据复制给返回的vo
        DeviceDetailVo vo = BeanUtil.toBean(device, DeviceDetailVo.class);
        //根据华为sdk获取设备信息
        //1.1一个华为sdk的方法，可参考官方文档
        ShowDeviceRequest showDeviceRequest = new ShowDeviceRequest();
        //通过iotId查询华为云设备
        showDeviceRequest.setDeviceId(iotId);
        //结合数据响应
        try {
            ShowDeviceResponse showDeviceResponse = iotClient.showDevice(showDeviceRequest);
            //获取华为平台下来的设备信息--启动状态(因为页面要展示而数据库没有)
            vo.setDeviceStatus(showDeviceResponse.getStatus());
            String activeTime = showDeviceResponse.getActiveTime();
            //时间
          if (StringUtils.isNotEmpty(activeTime)){

              //转换时间的格式
              LocalDateTime dateTime = LocalDateTimeUtil.parse(activeTime, DatePattern.UTC_MS_PATTERN);

              //转换时区
              dateTime = dateTime.atZone(ZoneId.from(ZoneOffset.UTC))
                      .withZoneSameInstant(ZoneId.of("Asia/Shanghai"))
                      .toLocalDateTime();
              vo.setActiveTime(dateTime);
          }
        } catch (Exception e) {
            throw new ServiceException("查询设备信息出错了");
        }
        return vo;
    }

    public   LocalDateTime getLocalDateTime(String activeTime) {
        //转换时间的格式
        LocalDateTime dateTime = LocalDateTimeUtil.parse(activeTime, "yyyyMMdd'T'HHmmss'Z'");

        //转换时区
        dateTime = dateTime.atZone(ZoneId.from(ZoneOffset.UTC))
                .withZoneSameInstant(ZoneId.of("Asia/Shanghai"))
                .toLocalDateTime();
        return dateTime;
    }

    @Override
    public List<DeviceShadowDataVo> queryServiceProperties(String iotId) {
        List<DeviceShadowDataVo> deviceShadowDataVoList = new ArrayList<>();
        //华为云上返回数据
        ShowDeviceShadowRequest showDeviceRequest = new ShowDeviceShadowRequest();
        showDeviceRequest.setDeviceId(iotId);
        try {
            ShowDeviceShadowResponse response = iotClient.showDeviceShadow(showDeviceRequest);
            List<DeviceShadowData> shadowList = response.getShadow();
            for (DeviceShadowData deviceShadowData : shadowList){
                //上报数据，里面属性和值
                DeviceShadowProperties reported = deviceShadowData.getReported();
               LinkedHashMap<String,Object> properties = (LinkedHashMap)reported.getProperties();
               //上报数据时间
                String eventTime = reported.getEventTime();
                LocalDateTime dateTime = LocalDateTimeUtil.parse(eventTime, "yyyyMMdd'T'HHmmss'Z'");

                //转换时区
                LocalDateTime  dateTimes = dateTime.atZone(ZoneId.from(ZoneOffset.UTC))
                        .withZoneSameInstant(ZoneId.of("Asia/Shanghai"))
                        .toLocalDateTime();
                //把map的每个数据转换成list
                deviceShadowDataVoList = properties.entrySet().stream().map(entry -> {
                    DeviceShadowDataVo vo = new DeviceShadowDataVo();
                    vo.setFunctionId(entry.getKey());
                    vo.setValue(entry.getValue().toString());
                    vo.setEventTime(dateTimes);
                    return vo;
                }).collect(Collectors.toList());
            }
        } catch (Exception e) {
            throw new ServiceException("上报数据出错了");
        }
        return deviceShadowDataVoList;
    }


}
